﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace myServer
{

    using MSNPSharp;
    using MSNPSharp.Core;
    using MSNPSharp.DataTransfer;


    public partial class frmMain : Form
    {
        // Create a Messenger object to use MSNPSharp.
        private Messenger messenger = new Messenger();

        private List<ConversationHandle> convhandles = new List<ConversationHandle>(0);

        private string User = "";
        private string Pass = "";

        public Messenger pMessenger
        {
            get
            {
                return messenger;
            }
        }
        
        public List<ConversationHandle> ConversationHandles
        {
            get
            {
                return convhandles;
            }
        }

        public frmMain()
        {
            InitializeComponent();

            // set the events that we will handle
            // remember that the nameserver is the server that sends contact lists, notifies you of contact status changes, etc.
            // a switchboard server handles the individual conversation sessions.
            messenger.NameserverProcessor.ConnectionEstablished += new EventHandler<EventArgs>(NameserverProcessor_ConnectionEstablished);
            messenger.Nameserver.SignedIn += new EventHandler<EventArgs>(Nameserver_SignedIn);
            messenger.Nameserver.SignedOff += new EventHandler<SignedOffEventArgs>(Nameserver_SignedOff);
            messenger.NameserverProcessor.ConnectingException += new EventHandler<ExceptionEventArgs>(NameserverProcessor_ConnectingException);
            messenger.Nameserver.ExceptionOccurred += new EventHandler<ExceptionEventArgs>(Nameserver_ExceptionOccurred);
            messenger.Nameserver.AuthenticationError += new EventHandler<ExceptionEventArgs>(Nameserver_AuthenticationError);
            messenger.Nameserver.ServerErrorReceived += new EventHandler<MSNErrorEventArgs>(Nameserver_ServerErrorReceived);
            messenger.ConversationCreated += new EventHandler<ConversationCreatedEventArgs>(messenger_ConversationCreated);
            //messenger.TransferInvitationReceived += new EventHandler<MSNSLPInvitationEventArgs>(messenger_TransferInvitationReceived);
            messenger.Nameserver.PingAnswer += new EventHandler<PingAnswerEventArgs>(Nameserver_PingAnswer);

            this.Icon = Properties.Resources.niMain_Icon;
            this.niMain.Icon = Properties.Resources.niMain_Icon;
        }

        #region Ballon Tip
        private delegate void SetBallonTipInfoDelegate(string tipText, int tipIcon);

        private void SetBallonTipInfoSynchronized(string tipText, int tipIcon)
        {
            this.niMain.BalloonTipText = tipText;
            //this.niMain.BalloonTipIcon = (ToolTipIcon)tipIcon;
            this.niMain.BalloonTipIcon = ToolTipIcon.Info;
            //this.niMain.Icon = Properties.Resources.niMain_Icon;
            this.niMain.ShowBalloonTip(1000);
        }

        private void SetBallonTipInfo(string tipText, int tipIcon)
        {
            this.Invoke(new SetBallonTipInfoDelegate(SetBallonTipInfoSynchronized), new object[] { tipText, tipIcon });
        }
        #endregion


        public void ReSignIn()
        {
            if (!this.User.Equals("") && !this.Pass.Equals(""))
            {
                if (messenger.Connected)
                {
                    SetStatus("Disconnecting from server");
                    messenger.Disconnect();
                }

                // set the credentials, this is ofcourse something every MSNPSharp program will need to implement.
                messenger.Credentials = new Credentials(this.User, this.Pass, MsnProtocol.MSNP15);


                // inform the user what is happening and try to connecto to the messenger network.			
                SetStatus("Connecting to server");
                messenger.Connect();

                miLogin.Tag = 1;
                miLogin.Text = "&Cancel";
            }
        }

//---------------------------
        private void NameserverProcessor_ConnectionEstablished(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(NameserverProcessor_ConnectionEstablished), sender, e);
                return;
            }

            messenger.Nameserver.AutoSynchronize = true;


            SetStatus("Connected to server");
        }

        private void Nameserver_SignedIn(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(Nameserver_SignedIn), sender, e);
                return;
            }

            SetStatus("Signed into the messenger network as " + messenger.Owner.Name);

            tmrKeepOnLine.Enabled = true;
            tmrKeepSignedIn.Enabled = false;

            // set our presence status
            miLogin.Tag = 2;
            miLogin.Text = "Sign off";

            messenger.Owner.Status = PresenceStatus.Busy;

        }

        private void Nameserver_SignedOff(object sender, SignedOffEventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler<SignedOffEventArgs>(Nameserver_SignedOff), sender, e);
                return;
            }

            SetStatus("Signed off from the messenger network");

            tmrKeepOnLine.Enabled = false;
            tmrKeepSignedIn.Enabled = true;

            miLogin.Tag = 0;
            miLogin.Text = "&Sign In";

        }

        private void Nameserver_ExceptionOccurred(object sender, ExceptionEventArgs e)
        {
            // ignore the unauthorized exception, since we're handling that error in another method.
            if (e.Exception is UnauthorizedException)
                return;

            //MessageBox.Show(e.Exception.ToString(), "Nameserver exception");
            SetStatus("Nameserver exception:" + e.Exception.Message);
        }

        private void NameserverProcessor_ConnectingException(object sender, ExceptionEventArgs e)
        {
            //MessageBox.Show(e.Exception.ToString(), "Connecting exception");
            SetStatus("Connecting failed");
        }

        private void Nameserver_AuthenticationError(object sender, ExceptionEventArgs e)
        {
            MessageBox.Show("Authentication failed, check your account or password.", e.Exception.InnerException.Message);
            SetStatus("Authentication failed");
        }

        private void Nameserver_ServerErrorReceived(object sender, MSNErrorEventArgs e)
        {
            // when the MSN server sends an error code we want to be notified.
            //MessageBox.Show(e.MSNError.ToString(), "Server error received");
            SetStatus("Server error received");
        }


        private delegate ConversationHandle CreateConversationDelegate(Conversation conversation, Contact remote);

        private ConversationHandle CreateConversationHandle(Conversation conversation, Contact remote)
        {
            foreach (ConversationHandle chandle in ConversationHandles)
            {
                if (chandle.CanAttach(remote.Mail) != -1)
                {
                    chandle.AttachConversation(conversation);
                    return chandle;
                }
            }

            // create a new conversation. However do not show the window untill a message is received.
            // for example, a conversation will be created when the remote client sends wants to send
            // you a file. You don't want to show the conversation form in that case.
            ConversationHandle conversationHandle = new ConversationHandle(conversation, this, remote.Mail);
            // do this to create the window handle. Otherwise we are not able to call Invoke() on the
            // conversation form later.
            ConversationHandles.Add(conversationHandle);
            return conversationHandle;
        }

        private void messenger_ConversationCreated(object sender, ConversationCreatedEventArgs e)
        {
            // check if the request is initiated remote or by this object
            // if it is initiated remote then we have to create a conversation form. Otherwise the 
            // form is already created and we don't need to create another one.
            if (e.Initiator == null)
            {
                // use the invoke method to create the form in the main thread, ONLY create the form after a contact joined our conversation.
                e.Conversation.Switchboard.ContactJoined += delegate(object switchboard, ContactEventArgs args)
                {
                    this.Invoke(new CreateConversationDelegate(CreateConversationHandle), new object[] { e.Conversation, args.Contact });
                };
            }
        }


//--------------------------

        private delegate void SetStatusDelegate(string status);
        private void SetStatus(string status)
        {
            if (InvokeRequired)
            {
                this.Invoke(new SetStatusDelegate(SetStatus), new object[] { status });
            }
            else
            {
                tbTrack.Text += status + "\r\n";
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void miLogin_Click(object sender, EventArgs e)
        {

            switch (Convert.ToInt32(miLogin.Tag))
            {
                case 0: // not connected -> connect
                    {
                        frmLogin frm = new frmLogin();
                        if ( frm.ShowDialog() == DialogResult.OK )
                        {

                            if (messenger.Connected)
                            {
                                SetStatus("Disconnecting from server");
                                messenger.Disconnect();
                            }

                            // save user and pass for resignin
                            this.User = frm.User;
                            this.Pass = frm.Pass;

                            // set the credentials, this is ofcourse something every MSNPSharp program will need to implement.
                            messenger.Credentials = new Credentials(frm.User, frm.Pass, MsnProtocol.MSNP15);


                            // inform the user what is happening and try to connecto to the messenger network.			
                            SetStatus("Connecting to server");
                            messenger.Connect();

                            miLogin.Tag = 1;
                            miLogin.Text = "&Cancel";
                        }

                        // note that Messenger.Connect() will run in a seperate thread and return immediately.
                        // it will fire events that informs you about the status of the connection attempt. 
                        // these events are registered in the constructor.
                    }
                    break;

                case 1: // connecting -> cancel
                    {
                        if (messenger.Connected)
                            messenger.Disconnect();

                        miLogin.Tag = 0;
                        miLogin.Text = "&Sign In";
                    }
                    break;

                case 2: // connected -> disconnect
                    {
                        if (messenger.Connected)
                            messenger.Disconnect();

                        miLogin.Tag = 0;
                        miLogin.Text = "&Sign In";
                    }
                    break;
            }
        }

        private void showToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowInTaskbar = true;

            this.showToolStripMenuItem.Enabled = false;
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            this.showToolStripMenuItem.Enabled = true;

            e.Cancel = true;
        }

        private int nextPing = 50;
        private void tmrKeepOnLine_Tick(object sender, EventArgs e)
        {
            if (nextPing > 0)
                nextPing--;
            if (nextPing == 0)
                messenger.Nameserver.SendPing();
        }

        void Nameserver_PingAnswer(object sender, PingAnswerEventArgs e)
        {
            nextPing = e.SecondsToWait;
        }

        // keep signed in
        private void tmrKeepSignedIn_Tick(object sender, EventArgs e)
        {
            if (!this.User.Equals("") && !this.messenger.Connected)
            {
                ReSignIn();
            }
        }
    }
}
